#include <time.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mosquitto.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#include <sys/types.h>
#include <signal.h>

#include "sqlite3.h"
#include "sample.h"
#include "logger.h"
#include "mosquitto.h"
#include "database.h"
#include "mqtt_config.h"

#define ARRAY_SIZE(x)       (sizeof(x)/sizeof(x[0]))

#define  PATH          "./aliyun.ini" 
//#define PASSWD          "dddiot@lingyun" 

int g_stop = 0;
int connect_sample=0;
void sig_stop(int signum)//如果传的参数是信号1，SIGUSR1则停止循环
{
	if(SIGUSR1 == signum)
	{
		g_stop = 1;
	}
}

void connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
	mqtt_user_data_t        *mqtt;

	int                      last_time;
	int                      now_time;
	sqlite3                 *db;
	char                     db_data[1024];
	int                      data_flag;

	if(database_open(&db, "mqttpub.db")!=0)
	{
     	log_error("cannot open database\n");  
	}
	printf("open database successfullly!\n");

	mqtt=(mqtt_user_data_t *)obj;
	if(rc==0)//rc=0 表示连接成功
	{

		log_info("connect_callback: connect successfullly.\n");
		if ((data_flag = database_get_id(db)) > 0)
		{
			log_info("start to send data to server from database!\n");
			if (database_query_data(db, db_data) < 0)//将断网时存储在数据库的数据拿初始化db_data
			{
				log_error("database_query_data() failure!\n");
				mosquitto_disconnect(mosq);
					
			}

			if(mosquitto_publish(mosq, NULL, mqtt->pub_topic, sizeof(db_data), db_data, 0, false)!=MOSQ_ERR_SUCCESS)
			{
				log_error("mosquitto_publish() failure:%s\n", strerror(errno));
				mosquitto_disconnect(mosq);

			}
			else
			{
				if(database_delete_data(db)!=0)
				{
					log_error("delete database failure\n");
					mosquitto_disconnect(mosq);
				}
			}
		}
	}

	sqlite3_close(db);
	mosquitto_disconnect(mosq);//短连接，每连上一次就调用一次回调
	connect_sample=0;
}


void disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
	log_warn("disconnect_callback: waiting for the reconnection.\n");
}


void publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
	log_info("publish_callback: send information successfully.\n");
}

static inline void print_usage(char *progname)
{
	printf("Usage:%s [option]...\n", progname);

	printf("%s is a socket server program, which used to verify client and echo back string from it\n", progname);
	printf("\n Mandatory arguments to long options are mandatory for short options too:\n");
	printf("-b(daemon)set progname runing on background\n");
 	printf("-p(--port):sepcify server listen port.\n");
 	printf("-s(--sn):sepcify name.\n");
 	printf("-n(--brokeraddress):sepcify host name.\n");
 	printf("-t(--sample_time):sepcify time to sample  .\n");
	printf("-h(--hellp):print this help information.\n");

	printf("\n Example:%s -b -p 8900\n", progname);
	return ;

}

int main(int argc, char **argv)
{
	int                      daemon_run=0;
	char                    *progname = NULL;
	int                      port;
	char                    *serv_ip;
	int                      opt;
	char                    *brokeraddress;
	int                      sample_time;
	struct hostent          *hostentp=NULL;
	char                    *ip=NULL;
	char                    *sn=NULL;
	struct mosquitto        *mosq;
	int                      sample_flag;
	char                     db_data[MAX_SIZE];
	int                      rv;
	char                     buff[512];
	int                      err;
	int                      data_flag;
	int                      now_time;
	int                      last_time;
    float                    temp_data;
    char                     time_data[32];
	char                     msg[MAX_SIZE];
	sqlite3                 *db;

	mqtt_user_data_t         mqtt;

	signal(SIGUSR1, sig_stop);//将sigusr1作为参数传给函数sig_stop
	struct option                    long_options[] = 
	{

		{"dameon", no_argument, NULL, 'b'},
		{"sample_time", required_argument,NULL, 't'},
		{"port", required_argument, NULL, 'p'},
		{"sn", required_argument, NULL, 'S'},
		{"help", no_argument, NULL, 'h'},
		{"brokeraddress",required_argument, NULL, 'n'},
	
		{ NULL, 0, NULL, 0}

	};

	progname = basename(argv[0]);
                                                           

	while((opt = getopt_long(argc, argv,"bp:s:t:n:h", long_options, NULL)) != -1)//(需要参数再加:);
	{
		switch(opt)
		{
			case 'b':
				daemon_run=1;
				break;

		
			case 'p':
				port=atoi(optarg);//string -> int
				break;
                        
			case 's':
				sn=optarg;
				break;         

			case 'n':
				brokeraddress=optarg;
				break;

			case 't':
		
				sample_time=atoi(optarg);
				break;
			case 'h':
				print_usage(progname);
				return EXIT_SUCCESS;

			default:
				break;
		}
	}
	if( !port )
	{
		print_usage(progname);
		return -1;
	}

	if(daemon_run)//设置程序背景运行
	{
		daemon(0, 0);
	}

	if(logger_init("stdout", LOG_LEVEL_INFO) <0)
	{
		fprintf(stderr, "inital logger system failure:%s\n", strerror(errno));	
		return -1;
	}

	if(database_open(&db, "mqttpub.db")!=0)
	{
		log_error("cannot open database\n");  
		return -1;
	}

	log_info("open database successfullly!\n");

	/*配置信息*/

	if (get_config(PATH, &mqtt)!=0)
	{
		log_error("get_config() failure!\n");
		return -1;
	}
	log_info("confige successfully!\n");


	mosquitto_lib_init();//使用mqtt的库函数前要先初始化
	mosq = mosquitto_new(mqtt.clientid , true, (void*)&mqtt);//返回一个新的客户端,mosq句柄,obj回调参数

//	printf("clientid:%s\n", mqtt.clientid);
	if(mosq==NULL)
	{
		log_error("mosquitto_new() failure:%s\n", strerror(errno));
		goto cleanup;
		return -1;
	}
	log_info("mosquitto_new() sucessfully\n");

	mosquitto_username_pw_set(mosq, mqtt.username, mqtt.passwd );
	mosquitto_connect_callback_set(mosq, connect_callback);
//	mosquitto_disconnect_callback_set(mosq, disconnect_callback);
//	mosquitto_publish_callback_set(mosq, publish_callback);
//	printf("username:%s, passwd:%s\n", mqtt.username, mqtt.passwd);

	last_time=time(NULL);
	while ( !g_stop)
	{
		now_time=time(NULL);
		mqtt.sample_flag = 0;
		if((now_time - last_time)>mqtt.sample_time)
		{
                /*采样温度 */
			log_info("start sampling!\n");
			/* sample_data初始化*/
			if (get_temp(&temp_data) != 0)
			{
				log_error("get temperature failure !: %s\n", strerror(errno));
				return -3;
			}
        	get_time( time_data );//获取时间,传buff传大小
			mqtt.sample_temp=temp_data;
			snprintf(mqtt.sample_data, sizeof(mqtt.sample_data), "%s/%s/%2.2f", mqtt.serial_no, time_data, temp_data);
	    	mqtt.sample_flag = 1;
			last_time = now_time;
		}

		if(mosquitto_connect(mosq, mqtt.brokeraddress, mqtt.port, mqtt.keep_alive)!=MOSQ_ERR_SUCCESS)
		{
	
		//	printf("brokeraddress:%s, port:%d\n", mqtt.brokeraddress, mqtt.port);
			log_error(" connect failure:%s\n", strerror);
			if(mqtt.sample_flag)
			{
				log_warn("data stored in database!\n");
				if(database_save_server(db, mqtt.sample_data)!=0)
				{
					log_error("database_save_server() failure\n");
					return -6;
				}
			}
		}
		else
		{
			log_info("mosq connect %s/%d sucessfully\n", mqtt.brokeraddress, mqtt.port);
				
			connect_sample =1;

			if(mqtt.sample_flag)
			{
				if(pack_json(&mqtt, msg)!=0)
				{
					printf("pack_cjson failure!\n");
				}
				printf("\n%s\n", msg);
				if(mosquitto_publish(mosq, NULL, mqtt.pub_topic, sizeof(msg), msg, 0, false)) 
            	{
            		log_error("mosquitto_publish() failure:%s\n", strerror(errno));
            	}
            	log_info("publish information successfully!");
	
				printf("pub_topic:%s\n", mqtt.pub_topic);
            	mqtt.sample_flag=0;
            }
		}

		err=mosquitto_loop(mosq, -1, 1);
		if(err)/*在while循环里调用loop()相当于loop_forever()，不阻塞*/
		{
			log_error("err : %d mosquitto_loop failure:%s\n", err, strerror(errno));

		}
		else
		{
			log_info("loop: continue to cycle\n");
		}

		if(connect_sample)
		{
			printf("connect_sample:%d\n", connect_sample);
			if(mosquitto_disconnect(mosq)!=MOSQ_ERR_SUCCESS)//短连接，每连上一次就调用一次回调
			{
				log_error("err = %ddisconnect failure!\n", err);
			}
			else
			{
				connect_sample=0;
				printf("disconnect successfullly , start to next connect\n");
			}
		}
		printf("--------------------------------------------------------------\n");
		sleep(1);
	}

cleanup:
	logger_term();
	mosquitto_destroy(mosq);
	mosquitto_lib_cleanup();
	sqlite3_close(db);
	return 0;
}


